package com.sweet.pack;

import com.sweet.enums.Charset;
import com.sweet.io.file.FileUtil;
import com.sweet.lang.StringUtil;
import com.sweet.util.ConvertUtil;
import lombok.Getter;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 文件合并
 *
 * @author limi
 * @date 2022/9/28 15:46
 */
public class FileMerge {
    /**
     * 线程池定义
     * 用于按代理商进行报表合并
     * 用于按游戏进行报表合并
     */
    private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(
            10,          //核心线程数,设置为>=代理商数量,不可设置过大,避免超出数据库最大连接数
            20,                     //最大线程数
            60L, TimeUnit.SECONDS,  //过期时间60秒
            new LinkedBlockingQueue<>());

    private static final String JS_BASE_PATH = "D:/work/gm/rb_admin/gm/web/src/main/resources/static" +
            "/js";

    private static final String CSS_BASE_PATH = "D:/work/gm/rb_admin/gm/web/src/main/resources/static" +
            "/css";
    private static final Map<String, String> JS_I18NS = new HashMap();

    static {
        JS_I18NS.put("/i18n/en.js", "/i18n/en.min.js");
        JS_I18NS.put("/i18n/ja.js", "/i18n/ja.min.js");
        JS_I18NS.put("/i18n/ko.js", "/i18n/ko.min.js");
        JS_I18NS.put("/i18n/th.js", "/i18n/th.min.js");
        JS_I18NS.put("/i18n/vi.js", "/i18n/vi.min.js");
        JS_I18NS.put("/i18n/zh_CN.js", "/i18n/zh_CN.min.js");
        JS_I18NS.put("/i18n/zh_TW.js", "/i18n/zh_TW.min.js");
    }

    /**
     * 配置信息
     */
    private static final List<MergeMap> JS_CONFIGS = new ArrayList() {{
        //国际化文件
        for (Map.Entry<String, String> i18n : JS_I18NS.entrySet()) {
            this.add(new MergeMap(
                    JS_BASE_PATH,
                    Arrays.asList(
                            i18n.getKey()
                    ),
                    i18n.getValue()
            ));
        }

        this.add(new MergeMap(
                JS_BASE_PATH,
                Arrays.asList(
                        "/layout/plus.js"
                ),
                "/layout/plus.min.js"
        ));
        this.add(new MergeMap(
                JS_BASE_PATH,
                Arrays.asList(
                        "/main/index/auth.js",
                        "/main/index/enum.js",
                        "/main/index/cache.js",
                        "/main/index/filter.js",
                        "/main/index/core.js",
                        "/main/index/permission.js",
                        "/main/index/http.js",
                        "/main/index/player.js",
                        "/main/index/util.js",
                        "/main/index/main.js",
                        "/main/index/pagination.js"
                ),
                "/main/index.min.js"
        ));
    }};

    /**
     * 最后一次更新时间
     */
    private static final File CONFIG_FILE = new File("D:/work/tool/config.txt");
    private static long LAST_MODIFY = 0;

    public static void main(String[] args) {
        //获取最后一次执行时间
        LAST_MODIFY = ConvertUtil.toLong(FileUtil.readFileToString(CONFIG_FILE, Charset.UTF8), 0);
        if (LAST_MODIFY < 1) {
            System.out.println("记录时间文件内容无效!");
            return;
        }

        //更新执行时间
        FileUtil.writeStringToFile(CONFIG_FILE, String.valueOf(System.currentTimeMillis()), Charset.UTF8, false);

        long start = System.currentTimeMillis();

        //定义计数器
        final CountDownLatch countDownLatch = new CountDownLatch(JS_CONFIGS.size());

        //多线程并行处理
        for (MergeMap map : JS_CONFIGS) {
            THREAD_POOL.execute(new MergeTask(map, true, countDownLatch));
        }

        //等待汇总任务完成
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("等待异常!");
        }

        //线程池结束
        THREAD_POOL.shutdown();

        System.out.println("合并耗时：" + (System.currentTimeMillis() - start) + "毫秒");
        System.out.println("合并时间：" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
    }

    /**
     * 文件合并
     *
     * @param config     文件配置
     * @param jsCompress JS压缩，仅针对js文件
     * @return 本次合并的文件数量
     */
    private static int merge(MergeMap config, boolean jsCompress) {
        //定义要合并的文件
        File file;
        List<File> mergeFiles = new ArrayList();
        int mergeCount = 0;
        for (String source : config.getSources()) {
            //获取文件
            file = new File(config.getBasePath() + source);
            if (!file.exists() || !file.isFile()) {
                throw new RuntimeException("文件[" + source + "]不存在!");
            }

            //加入合并列表
            mergeFiles.add(file);

            //检查修改时间
            if (file.lastModified() >= LAST_MODIFY) {
                mergeCount++;
            }
        }

        //检查合并列表
        if (mergeCount == 0) {
            return 0;
        }

        //定义合并内容
        String text;
        StringBuilder content = new StringBuilder();
        for (File mergeFile : mergeFiles) {
            text = FileUtil.readFileToString(mergeFile, Charset.UTF8);
            if (StringUtil.isNotBlank(text)) {
                content.append(text).append("\n\r");
            }
        }

        //文件压缩
        String resultContent = content.toString();
        if (StringUtil.isNotBlank(resultContent) && jsCompress) {
            try {
                String code = JsUtil.compress(resultContent);
                if (StringUtil.isNotBlank(code)) {
                    resultContent = code;
                }
            } catch (Exception e) {
                throw new RuntimeException("压缩合并文件发生异常,target=" + config.getTarget() + ",message=" + e.getMessage());
            }
        }

        //创建文件
        FileUtil.createText(config.getBasePath() + config.getTarget(), resultContent);

        System.out.println("合并压缩：" + config.getTarget());

        //返回压缩数量
        return mergeFiles.size();
    }

    @Getter
    private static class MergeMap {
        /**
         * 基础路径
         */
        private String basePath;

        /**
         * 源文件
         */
        private List<String> sources;

        /**
         * 目标文件
         */
        private String target;

        public MergeMap(String basePath, List<String> sources, String target) {
            this.basePath = basePath;
            this.sources = sources;
            this.target = target;
        }
    }

    /**
     * 合并任务
     */
    private static class MergeTask implements Runnable {
        private MergeMap config;
        private boolean jsCompress;
        private CountDownLatch countDownLatch;

        public MergeTask(MergeMap config, boolean jsCompress,
                         CountDownLatch countDownLatch) {
            this.config = config;
            this.jsCompress = jsCompress;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                //执行合并任务
                merge(this.config, this.jsCompress);
            } catch (Exception e) {
                System.out.println("合并发生异常,cause=" + e.getMessage());
            } finally {
                this.countDownLatch.countDown();
            }
        }
    }
}